package com.lianqi.emcpframework.data.masker;

import com.lianqi.emcpframework.data.masker.annotation.MaskData;
import com.lianqi.emcpframework.data.masker.stratgey.DataMaskStrategy;
import com.lianqi.emcpframework.utils.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @program emcp-framework
 * @ClassName DataMaskerProvider
 * @description: 数据脱敏组件提供者
 * @author: sky
 * @create: 2019/05/27 09:45
 */
public class DataMaskerProvider {

    @Autowired(required = false)
    private final List<MaskerDefinition> definitions = new ArrayList<>();


    /**
     * 执行数据脱敏
     *
     * @param source  脱敏对象
     * @param maskMap 自定义脱敏方式  如果不为null 执行自定义脱敏
     */
    public void doMaskCustom(Object source, Map<String, DataMaskStrategy> maskMap) {
        if (CollectionUtils.isEmpty(maskMap)){
            return;
        }
        Field[] fields = ObjectUtils.getAllFields(source);
        for (Field field : fields){
            String fieldName = field.getName();
            if (maskMap.containsKey(fieldName) && maskMap.get(fieldName) != null){
                doMaskWithStrategy(field,source,maskMap.get(fieldName));
            }
        }
    }
    /**
     * 执行数据脱敏
     *
     * @param source  脱敏对象
     * @param maskMap 自定义脱敏方式  如果不为null 执行自定义脱敏
     */
    public void doMask(Object source, Map<String, DataMaskStrategy> maskMap) {
        doMask(source,maskMap,null);
    }

    /**
     * 执行数据脱敏
     *
     * @param source 脱敏对象
     * @param adopts 指定脱敏字段集合  如不为null 只为指定的字段脱敏
     */
    public void doMask(Object source, String... adopts) {
       doMask(source,null,adopts);
    }

    /**
     * 执行数据脱敏
     *
     * @param source  脱敏对象
     * @param maskMap 自定义脱敏方式  如果不为null 执行自定义脱敏
     * @param adopts  指定脱敏字段集合  如不为null 只为指定的字段脱敏
     */
    public void doMask(Object source, Map<String, DataMaskStrategy> maskMap, String... adopts) {
        Field[] fields = ObjectUtils.getAllFields(source);
        List<String> adoptList = new ArrayList<>();
        if (adopts != null && adopts.length > 0) {
            adoptList = Arrays.asList(adopts);
        }
        for (Field field : fields) {
            String fieldName = field.getName();
            if (!CollectionUtils.isEmpty(adoptList)
                    && !adoptList.contains(fieldName)) {
                continue;
            } else if (!CollectionUtils.isEmpty(maskMap) && maskMap.get(fieldName) != null) {
                doMaskWithStrategy(field, source, maskMap.get(fieldName));
            } else {
                execute(source, field);
            }
        }
    }


    private void execute(Object source, Field field) {
        MaskerDefinition definition = definitions.stream().filter(d ->
                d.support(field)).findAny().orElse(null);
        if (definition != null) {
            try {
                field.set(source, definition.maskValue(field, source));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取脱敏策略
     *
     * @param type
     * @param supportType
     * @return
     */
    public DataMaskStrategy getDataMaskStrategy(MaskFieldType type, Class<?> supportType) {
        MaskerDefinition definition = definitions.stream().filter(d ->
                d.supportType() == supportType).findAny().orElse(null);
        if (definition != null) {
            return definition.getStrategy(type);
        }
        return null;
    }

    /**
     * 添加脱敏策略
     *
     * @param type
     * @param strategy
     */
    public void addMaskStrategy(MaskFieldType type, DataMaskStrategy<?> strategy) {
        if (strategy != null) {
            MaskerDefinition definition = definitions.stream().filter(d ->
                    d.supportType() == strategy.supportType()).findAny().orElse(null);
            if (definition != null) {
                definition.addDataMaskStrategy(type, strategy);
            }
        }
    }

    private void doMaskWithStrategy(Field field, Object source, DataMaskStrategy strategy) {
        String fieldName = field.getName();
        try {
            field.setAccessible(true);
            Object value = field.get(source);
            MaskData ann = field.getAnnotation(MaskData.class);
            field.set(source, strategy.maskValue(value, ann));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加脱敏执行类
     *
     * @param definition
     */
    public void addMasker(MaskerDefinition definition) {
        if (definition != null) {
            definitions.add(definition);
        }
    }


}
